﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.TreeSharp;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using Action = Styx.TreeSharp.Action;

namespace TuanHA_Hunter
{
    public partial class Classname : CombatRoutine
    {
        //[DllImport("user32.dll")]
        //private static extern IntPtr GetForegroundWindow();

        //[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        //private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        //private static string GetActiveWindowTitle()
        //{
        //    const int nChars = 256;
        //    IntPtr handle = IntPtr.Zero;
        //    StringBuilder Buff = new StringBuilder(nChars);
        //    handle = GetForegroundWindow();

        //    if (GetWindowText(handle, Buff, nChars) > 0)
        //    {
        //        return Buff.ToString();
        //    }
        //    return null;
        //}

        #region Delegates

        public delegate WoWPoint LocationRetriverDelegate(object context);

        #endregion

        #region Basic Functions

        public override bool WantButton
        {
            get { return true; }
        }

        public override WoWClass Class
        {
            get { return WoWClass.Hunter; }
        }

        public override string Name
        {
            get { return "TuanHA Hunter [Public Release]"; }
        }

        //private static Composite _restBehavior()
        //{
        //    return new LockSelector(
        //        RestRotation());
        //}

        public override Composite RestBehavior
        {
            get { return RestRotation(); }
        }

        //private static Composite _preCombatBuffsBehavior()
        //{
        //    return new LockSelector(
        //        MainRotation());
        //}

        public override Composite PreCombatBuffBehavior
        {
            //get { return _preCombatBuffsBehavior(); }
            get { return MainRotation(); }
        }

        //public override Composite PullBuffBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //public override Composite PullBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //public override Composite CombatBuffBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //private static Composite _combatBehavior()
        //{
        //    return new LockSelector(
        //        MainRotation());
        //}

        public override Composite CombatBehavior
        {
            //get { return _combatBehavior(); }
            get { return MainRotation(); }
        }

        //public override Composite HealBehavior
        //{
        //    get { return MainRotation(); }
        //}

        //public override Composite MoveToTargetBehavior
        //{
        //    get { return CreateMoveToLosBehavior(); }
        //}

        private static LocalPlayer Me
        {
            get { return StyxWoW.Me; }
        }


        public override void Initialize()
        {
            Logging.Write("");
            Logging.Write("Hello " + Me.Level + " " + Me.Race + " " + Me.Class);
            Logging.Write("Thank you for using TuanHA Hunter Special Edition");
            Logging.Write("");

            //Disable for speed
            //Lua.Events.AttachEvent("GROUP_ROSTER_UPDATE", UpdateGroupChangeEvent);
            Lua.Events.AttachEvent("ACTIVE_TALENT_GROUP_CHANGED", UpdateStatusEvent);
            Lua.Events.AttachEvent("PLAYER_TALENT_UPDATE", UpdateMyTalentEvent);
            Lua.Events.AttachEvent("GLYPH_ADDED", UpdateMyGlyphEvent);
            //Lua.Events.AttachEvent("WORLD_MAP_NAME_UPDATE", UpdateCurrentMapEvent);

            //BotEvents.Player.OnMapChanged += UpdateCurrentMapEvent;
            BotEvents.OnBotStarted += OnBotStartedEvent;

            //Set Camera angle so you never have problem with it
            //console cameraSmoothTrackingStyle 0 (credit by alxaw - member of CLU dev team) 
            //Lua.DoString("RunMacroText(\"/console cameraSmoothTrackingStyle 1\")");
            PetSpells.Clear();
            THSettings.Instance.UpdateStatus = true;
        }

        public override void OnButtonPress()
        {
            var gui = new THHunterForm();
            gui.ShowDialog();
        }

        #endregion

        #region Function After this Region Order Alphabetically

        #endregion

        #region GetUnits

        private static IEnumerable<WoWUnit> GetAllUnits()
        {
            return
                ObjectManager.GetObjectsOfType<WoWUnit>(true, false)
                             .Where(
                                 u =>
                                 ValidUnit(u) &&
                                 u.Distance2DSqr < THSettings.Instance.SearchRange*THSettings.Instance.SearchRange)
                             .ToList();
        }

        private static readonly List<WoWPlayer> NearbyUnFriendlyPlayers = new List<WoWPlayer>();
        private static readonly List<WoWUnit> NearbyUnFriendlyUnits = new List<WoWUnit>();
        private static DateTime GetUnitsLast;

        private static Composite GetUnits()
        {
            return new Action(delegate
                {
                    if (GetUnitsLast + TimeSpan.FromMilliseconds(THSettings.Instance.SearchInterval) > DateTime.Now)
                    {
                        return RunStatus.Failure;
                    }

                    NearbyUnFriendlyPlayers.Clear();
                    NearbyUnFriendlyUnits.Clear();

                    foreach (var unit in GetAllUnits())
                    {
                        if (!unit.IsValid)
                        {
                            continue;
                        }
                        if (IsEnemy(unit))
                        {
                            NearbyUnFriendlyUnits.Add(unit);

                            var player = unit as WoWPlayer;
                            if (player != null && Me.IsInInstance)//Do not attack world player
                            {
                                NearbyUnFriendlyPlayers.Add(player);
                            }
                        }
                    }
                    GetUnitsLast = DateTime.Now;
                    return RunStatus.Failure;
                });
        }

        #endregion

        #region GetUnitAttack

        //private static WoWUnit UnitAttack;
        //private static WoWUnit UnitAttackPet;

        //private static void GetUnitAttack()
        //{
        //    UnitAttack = null;
        //    UnitAttackPet = null;

        //    //if (THSettings.Instance.SAutoTarget)
        //    //{
        //    ////using (StyxWoW.Memory.AcquireFrame())
        //    {
        //        UnitAttack = (from unit in NearbyUnFriendlyUnits
        //                      //Only search Target if in instance
        //                      //where Me.IsInInstance
        //                      orderby unit.HealthPercent ascending
        //                      //attack any unit if not in dungeon/raid
        //                      where unit.Combat
        //                      //where unit.CurrentTarget!=null
        //                      //only attack unit not tagged
        //                      where
        //                          unit.IsTargetingMeOrPet ||
        //                          unit.IsTargetingMyPartyMember ||
        //                          unit.IsTargetingMyRaidMember ||
        //                          unit.IsPlayer && (Me.CurrentMap.IsBattleground || Me.CurrentMap.IsArena)
        //                      where AttackableValid(unit)
        //                      select unit).FirstOrDefault();

        //        //if it pet, try to find a player
        //        if (UnitAttack != null && UnitAttack.IsValid && !UnitAttack.IsPlayer && !Me.CurrentMap.IsRaid &&
        //            !Me.CurrentMap.IsDungeon)
        //        {
        //            UnitAttackPet = UnitAttack;
        //            UnitAttack = (from unit in NearbyUnFriendlyUnits
        //                          where unit.IsPlayer
        //                          orderby unit.Distance ascending
        //                          where unit.Combat && unit.IsTargetingMeOrPet || Me.CurrentMap.IsBattleground
        //                          where AttackableValid(unit)
        //                          select unit).FirstOrDefault();

        //            //can't find a player, kill the pet
        //            if (UnitAttack == null && UnitAttackPet != null && UnitAttackPet.IsValid)
        //            {
        //                UnitAttack = UnitAttackPet;
        //            }
        //        }
        //    }
        //    //}
        //}

        #endregion

        #region GroupMembers

        //private static IEnumerable<WoWPartyMember> GroupMembers
        //{
        //    get { return !Me.GroupInfo.IsInRaid ? Me.GroupInfo.PartyMembers : Me.GroupInfo.RaidMembers; }
        //}

        #endregion

        #region Nested type: LockSelector

        /// <summary>
        /// This behavior wraps the child behaviors in a 'FrameLock' which can provide a big performance improvement 
        /// if the child behaviors makes multiple api calls that internally run off a frame in WoW in one CC pulse.
        /// Thank Singular
        /// </summary>
        //private static class LockSelector : PrioritySelector
        //{
        //    public LockSelector(params Composite[] children)
        //        : base(children)
        //    {
        //    }
        //    public override RunStatus Tick(object context)
        //    {
        //        ////using (StyxWoW.Memory.AcquireFrame())
        //        {
        //            return base.Tick(context);
        //        }
        //    }
        //}

        #endregion

        #region Pulse
        private static DateTime LastSwitch;

        private static DateTime BurstLast;
        private static bool Burst;

        public override void Pulse()
        {
            if (!Me.IsValid ||
                !THSettings.Instance.AttackOOC && !Me.Combat ||
                !Me.IsAlive ||
                !StyxWoW.IsInWorld)
            {
                return;
            }

            if (THSettings.Instance.UpdateStatus)
            {
                UpdateStatus();
            }
            else
            {
                ObjectManager.Update();

                //Pause
                if (THSettings.Instance.PauseKeyUse && THSettings.Instance.PauseKey != 0)
                {
                    //AoE Mode
                    if (GetAsyncKeyState(Keys.LControlKey) < 0 &&
                        GetAsyncKeyState(IndexToKeys(THSettings.Instance.PauseKey)) < 0 &&
                        LastSwitch.AddSeconds(1) < DateTime.Now) // && GetActiveWindowTitle() == "World of Warcraft")
                    {
                        if (THSettings.Instance.Pause)
                        {
                            THSettings.Instance.Pause = false;
                            LastSwitch = DateTime.Now;
                            Logging.Write("Pause Mode is OFF, Ctrl + " +
                                          IndexToKeys(THSettings.Instance.PauseKey) +
                                          " to Override bot action.");
                            //Lua.DoString("RunMacroText(\"/script msg='Pause Mode OFF' print(msg)\")");
                        }
                        else
                        {
                            THSettings.Instance.Pause = true;
                            LastSwitch = DateTime.Now;
                            Logging.Write("Pause Mode is ON, Ctrl + " +
                                          IndexToKeys(THSettings.Instance.PauseKey) +
                                          " to resume bot action.");
                            //Lua.DoString("RunMacroText(\"/script msg='Pause Mode ON' print(msg)\")");
                        }
                    }
                }

                //Auto Disactivate Burst after a Timer or Me get CC
                if (Burst && BurstLast < DateTime.Now)
                {
                    Burst = false;
                    //BurstLast = DateTime.Now;
                    Logging.Write("Burst Mode is OFF");
                    //Lua.DoString("RunMacroText(\"/script msg='Burst Mode OFF' print(msg)\")");
                }

                //Burst on Cooldown
                if (THSettings.Instance.BurstKey == 1 &&
                    Burst == false &&
                    Me.Combat)
                {
                    BurstLast = DateTime.Now.AddSeconds(15);
                    Logging.Write("Burst Mode Activated On Cooldown");
                    Burst = true;
                }

                if (THSettings.Instance.BurstKey == 2 &&
                    Burst == false &&
                    Me.Combat &&
                    Attackable(Me.CurrentTarget, 40) &&
                    Me.CurrentTarget.IsBoss)
                {
                    BurstLast = DateTime.Now.AddSeconds(15);
                    Logging.Write("Burst Mode Activated On Cooldown (Boss Only)");
                    Burst = true;
                }

                //Burst on Bloodlust
                if (THSettings.Instance.BurstKey == 3 && Burst == false &&
                    (Me.HasAura("Bloodlust") || Me.HasAura("Heroism") || Me.HasAura("Time Warp") ||
                     Me.HasAura("Ancient Hysteria")))
                {
                    BurstLast = DateTime.Now.AddSeconds(15);
                    Logging.Write("Burst Mode Activated On Bloodlust/Heroism/Time Warp/Ancient Hysteria");
                    Burst = true;
                }

                //Burst On Lose Control
                if (THSettings.Instance.BurstKey == 4 && Burst == false &&
                    DebuffCCDuration(Me, 3000))
                {
                    BurstLast = DateTime.Now.AddSeconds(15);
                    Logging.Write("Burst Mode Activated on Lose Control");
                    Burst = true;
                }

                //Burst On My Health Below
                if (THSettings.Instance.BurstKey == 5 && Burst == false &&
                    Me.HealthPercent < THSettings.Instance.BurstHP)
                {
                    BurstLast = DateTime.Now.AddSeconds(15);
                    Logging.Write("Burst Mode Activated on My Health Low");
                    Burst = true;
                }

                //Burst On Enemy Health Below
                if (THSettings.Instance.BurstKey == 6 &&
                    Burst == false &&
                    Attackable(Me.CurrentTarget, 40) &&
                    !Me.CurrentTarget.IsPet &&
                    Me.HealthPercent > THSettings.Instance.UrgentHeal &&
                    Me.CurrentTarget.HealthPercent < THSettings.Instance.BurstHP)
                {
                    BurstLast = DateTime.Now.AddSeconds(15);
                    Logging.Write("Burst Mode Activated on Enemy Health Low");
                    Burst = true;
                }

                //Burst by key press
                if (THSettings.Instance.BurstKey > 6)
                {
                    //Burst Mode
                    if (GetAsyncKeyState(Keys.LControlKey) < 0 &&
                        GetAsyncKeyState(IndexToKeys(THSettings.Instance.BurstKey - 6)) < 0 &&
                        LastSwitch.AddSeconds(1) < DateTime.Now) // && GetActiveWindowTitle() == "World of Warcraft")
                    {
                        if (Burst)
                        {
                            Burst = false;
                            LastSwitch = DateTime.Now;
                            Logging.Write("Burst Mode is OFF, Ctrl + " +
                                          IndexToKeys(THSettings.Instance.BurstKey - 6) +
                                          " to Turn Burst Mode ON.");
                            //Lua.DoString("RunMacroText(\"/script msg='Burst Mode OFF' print(msg)\")");
                        }
                        else
                        {
                            Burst = true;
                            LastSwitch = DateTime.Now;
                            BurstLast = DateTime.Now.AddSeconds(15);
                            Logging.Write("Burst Mode is ON for 15 seconds, Ctrl + " +
                                          IndexToKeys(THSettings.Instance.BurstKey - 6) +
                                          " to Turn Burst Mode OFF.");
                            //Lua.DoString("RunMacroText(\"/script msg='Burst Mode ON' print(msg)\")");
                        }
                    }
                }

                //Spell Need To Use on Pulse
                if (LastFeignDeath + TimeSpan.FromMilliseconds(2000) < DateTime.Now)
                {
                    UseTrinket();
                    SilencingShotInterrupt();
                    DisengageVoid();
                    ExhilarationVoid();
                    DeterrenceHPVoid();
                    DeterrenceUnitVoid();
                    SpiritMendVoid();
                    FeignDeathVoid();
                    StopCastingCheck();
                    ScatterShotInterrupt();
                    //SteadyShotSteadyFocusStop();
                }
            }
        }

        #endregion

        #region MainRotation

        private static bool _aoEModeOn;
        private static bool IsOverrideModeOn;
        private static WoWUnit MyLastTarget;
        private static DateTime TickMilisecondTotal;
        //private static DateTime DoNotMove;


        private Composite MainRotation()
        {
            return new PrioritySelector(
                HoldFeignDeath(),
                Hold(),
                //new Throttle(TimeSpan.FromMilliseconds(THSettings.Instance.SearchInterval), GetUnits()),
                GetUnits(),
                new Throttle(TimeSpan.FromSeconds(10), Readiness()),
                new Decorator(
                    ret => THSettings.Instance.Pause,
                    new Action(delegate { return RunStatus.Success; })),
                FocusFreezingTrap(),
                TargetFreezingTrap(),
                ScareBeast(),
                new Decorator(
                    ret =>
                    THSettings.Instance.UpdateStatus,
                    new Action(delegate
                        {
                            //Logging.Write("Need Update Status first");
                            //UpdateStatus();
                            return RunStatus.Success;
                        })),
                //new Decorator(
                //    ret => (Me.HasAura("Resurrection Sickness") ||
                //            !StyxWoW.IsInWorld ||
                //            !Me.IsValid),
                //    new Action(delegate
                //        {
                //            THSettings.Instance.UpdateStatus = true;
                //            Logging.Write(LogLevel.Diagnostic,
                //                          "Resurrection Sickness or not in WoW, Skip Main Rotation.");
                //            return RunStatus.Success;
                //        })),
                //Trying to stop bot movement while casting
                new Decorator(
                    ret =>
                    TreeRoot.Current.Name != "LazyRaider" &&
                    TreeRoot.Current.Name != "Raid Bot" &&
                    TreeRoot.Current.Name != "Combat Bot" &&
                    (Me.IsCasting || Me.IsChanneling),
                    new Action(delegate { return RunStatus.Success; })
                    ),
                new Action(delegate
                    {
                        if (!IsOverrideModeOn &&
                            //Do not stop movement in LazyRaider if SMoveToTarget enabled
                            //TreeRoot.Current.Name != "LazyRaider" &&
                            (GetAsyncKeyState(Keys.LButton) < 0 &&
                             GetAsyncKeyState(Keys.RButton) < 0) ||
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.StrafleLeft)) < 0 &&
                            IndexToKeys(THSettings.Instance.StrafleLeft) != Keys.None ||
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.Forward)) < 0 &&
                            IndexToKeys(THSettings.Instance.Forward) != Keys.None ||
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.StrafleRight)) < 0 &&
                            IndexToKeys(THSettings.Instance.StrafleRight) != Keys.None ||
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.TurnLeft)) < 0 &&
                            IndexToKeys(THSettings.Instance.TurnLeft) != Keys.None ||
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.Backward)) < 0 &&
                            IndexToKeys(THSettings.Instance.Backward) != Keys.None ||
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.TurnRight)) < 0 &&
                            IndexToKeys(THSettings.Instance.TurnRight) != Keys.None)
                        {
                            //Logging.Write(LogLevel.Diagnostic, "Override mode on. Stop all bot movement");
                            IsOverrideModeOn = true;
                        }

                        if (IsOverrideModeOn &&
                            //Do not stop movement in LazyRaider if SMoveToTarget enabled
                            //TreeRoot.Current.Name != "LazyRaider" &&
                            (GetAsyncKeyState(Keys.LButton) >= 0 ||
                             GetAsyncKeyState(Keys.RButton) >= 0) &&
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.StrafleLeft)) >= 0 &&
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.Forward)) >= 0 &&
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.StrafleRight)) >= 0 &&
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.TurnLeft)) >= 0 &&
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.Backward)) >= 0 &&
                            GetAsyncKeyState(IndexToKeys(THSettings.Instance.TurnRight)) >= 0)
                        {
                            //Logging.Write(LogLevel.Diagnostic, "Override mode off. Bot movement resume");
                            IsOverrideModeOn = false;
                        }

                        if (GetAsyncKeyState(Keys.RControlKey) < 0 && GetAsyncKeyState(Keys.F9) < 0)
                        {
                            Logging.Write("MainRotation take " +
                                          Math.Round((DateTime.Now -
                                                      TickMilisecondTotal).TotalMilliseconds) +
                                          " ms");
                            TickMilisecondTotal = DateTime.Now;
                        }
                        if (GetAsyncKeyState(Keys.RControlKey) < 0 && GetAsyncKeyState(Keys.F10) < 0)
                        {
                            WriteTargetInfo();
                        }

                        //Get target back after a fear
                        if (Me.CurrentTarget != null && Me.CurrentTarget.IsValid && MyLastTarget != Me.CurrentTarget)
                        {
                            MyLastTarget = Me.CurrentTarget;
                        }

                        //Clear Target if dead and still in combat
                        if (Me.CurrentTarget != null && !Me.CurrentTarget.IsAlive && Me.Combat)
                        {
                            Lua.DoString("RunMacroText(\"/cleartarget\")");
                        }

                        //Clear Backlist Target
                        if (Me.CurrentTarget != null &&
                            Blacklist.Contains(Me.CurrentTarget.Guid, BlacklistFlags.All))
                        {
                            Lua.DoString("RunMacroText(\"/cleartarget\")");
                        }

                        //Clear Target if walk away from friendly
                        if (Me.CurrentTarget != null && !Me.CurrentTarget.IsPlayer &&
                            Me.CurrentTarget.IsFriendly &&
                            Me.CurrentTarget.IsSafelyBehind(Me))
                        {
                            Lua.DoString("RunMacroText(\"/cleartarget\")");
                        }

                        return RunStatus.Failure;
                    }
                    ),
                new Throttle(TimeSpan.FromMilliseconds(500), AutoTarget()),
                //new Throttle(TimeSpan.FromMilliseconds(5000), AutoSwapFocus()),
                new Throttle(TimeSpan.FromMilliseconds(500), SetAutoAttack()),
                new Throttle(TimeSpan.FromSeconds(10), UseRacial()),
                new Throttle(TimeSpan.FromSeconds(10), UseProfession()),
                HoldDungeon(),
                new Decorator(
                    ret =>
                    UseRotation == "HunterBeastMastery",
                    HunterBeastMasteryRotation()
                    ),
                new Decorator(
                    ret =>
                    UseRotation == "HunterMarksmanship",
                    HunterMarksmanshipRotation()
                    ),
                new Decorator(
                    ret =>
                    UseRotation == "HunterSurvival",
                    HunterSurvivalRotation()
                    )
                );
        }

        #endregion
    }
}